/**
 * MyDataSourceTransactionManagerAutoConfiguration.java 2016年11月15日 11:41
 * <p>
 * Copyright (c) 2010-2016 yinghezhong Inc. All rights reserved.
 *
 * @Description
 * @version 1.0
 */
package com.ql.cloud.framework.config.dao.config.datasource;

import com.ql.cloud.commons.base.component.SpringContextHolder;
import org.aspectj.internal.lang.reflect.PointcutImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.aspectj.AspectJAroundAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;

/**
 * 自定义事务
 *
 * @author 齐龙
 * @date 2016年11月15日 11:41
 *
 */
@Configuration
public class TransactionManagerConfiguration extends DataSourceTransactionManagerAutoConfiguration {
    private Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private ConfigurableApplicationContext applicationContext;
    /**
     * 自定义事务 MyBatis自动参与到spring事务管理中，无需额外配置，只要org.mybatis.spring.
     * SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可，否则事务管理会不起作用。
     * 
     * @return
     */
    @Bean(name = "transactionManager")
    public DataSourceTransactionManager transactionManagers() {
        log.info("-------------------- transactionManager init ---------------------");
        ReadWriteRoutingDataSource dataSource = (ReadWriteRoutingDataSource) applicationContext.getBean("readWriteRoutingDataSource");
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "transactionInterceptor")
    public TransactionInterceptor transactionInterceptor() {
        MyTransactionInterceptor transactionInterceptor = new MyTransactionInterceptor();
        DataSourceTransactionManager transactionManager = transactionManagers();
        ReadWriteDataSourceProcessor readWriteDataSourceProcessor = (ReadWriteDataSourceProcessor) applicationContext.getBean("readWriteDataSourceProcessor");
        // 事物管理器
        transactionInterceptor.setTransactionManager(transactionManager);
        TransactionProperties properties = applicationContext.getBean(TransactionProperties.class);
        transactionInterceptor.setReadWriteDataSourceProcessor(readWriteDataSourceProcessor);
        transactionInterceptor.setTransactionAttributes(properties.getProperties());
        return transactionInterceptor;
    }

    @Bean
    public NameMatchTransactionAttributeSource nameMatchTransactionAttributeSource(){
        NameMatchTransactionAttributeSource attributeSource = new NameMatchTransactionAttributeSource();
        TransactionProperties properties = applicationContext.getBean(TransactionProperties.class);
        attributeSource.setProperties(properties.getProperties());
        return attributeSource;
    }

    @Bean(name = "readWriteDataSourceProcessor")
    public ReadWriteDataSourceProcessor getReadWriteDataSourceProcessor(){
        ReadWriteDataSourceProcessor processor = new ReadWriteDataSourceProcessor();
        processor.setForceChoiceReadWhenWrite(true);
        return processor;
    }

    @Bean
    public Pointcut pointcut(){
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        TransactionProperties transactionProperties = applicationContext.getBean(TransactionProperties.class);
        pointcut.setExpression(transactionProperties.getPointCut());
        return pointcut;
    }
    @Bean
    public Advisor advisor(){
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        MyTransactionInterceptor transactionInterceptor = (MyTransactionInterceptor) applicationContext.getBean("transactionInterceptor");
        advisor.setAdvice(transactionInterceptor);
        advisor.setPointcut(pointcut());
        return advisor;
    }
}
